Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bluetooth IP Address Advertisement #325

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

connorh315
Copy link

Sometimes the service discovery is a bit slow (or non-existent on poorly managed networks). This is an alternative method for Airplay senders to detect receivers. It involves frequently sending out the IP address of the receiver over Bluetooth. If a sender is in range and has Bluetooth enabled it will pick up the BLE advert, and then send a special "GET /info" request to the IP address in question to receive data similar to that which is broadcast by the DNS-SD. The IP address advertisement leads to more reliable discovery from testing.

Only works on Linux currently, requires sudo (as well as a BLE interface too). Enable this with the -btip argument

@connorh315
Copy link
Author

I'm not very good at C, so I had no idea how to constrict most of the code here to be only run on a Linux system as I know that will be a big problem as if this is merged it means that no other platform will be able to build.

@fduncanh
Copy link
Collaborator

fduncanh commented Aug 18, 2024

I guess this is "BTLE" (BLE) described here:

https://support.apple.com/guide/deployment/use-airplay-dep9151c4ace/web

https://www.bluetooth.com/bluetooth-resources/the-bluetooth-low-energy-primer/

https://www.allaboutcircuits.com/technical-articles/exploring-the-basics-of-bluetooth-low-energy-a-beginners-guide-to-ble/

https://github.com/microsoft/windows-universal-samples/tree/main/Samples/BluetoothAdvertisement

it's present in windows and macOS too.

  • so uxplay needs to detect if BLE service is present on the host, and if so, send a DNS_SD-equivalent advertisement periodically.
    will the reply come over bluetooth too, on on the regular network? (I didnt read the doc yet)

@connorh315
Copy link
Author

That's it, Apple describes it as the "Bluetooth IP Address Advertisement". BLE avertisements can be sent out on Windows and macOS too - I might have a go at implementing it on Windows later, I'll just need to take a look at existing code and figure out how one implements different libraries for each platform etc. as I've never worked in C before.

  • so uxplay needs to detect if BLE service is present on the host, and if so, send a DNS_SD-equivalent advertisement periodically.

will the reply come over bluetooth too, on on the regular network? (I didnt read the doc yet)

Currently, the code is set so that it attempts to set up a BLE interface, if it doesn't find one/an error occurs (usually that it doesn't have the privileges as the program needs to be run as sudo) then it sends a message in the console saying it is disabled for the session as there was an error and gives up using BLE. It doesn't exactly send a DNS-SD advertisement over bluetooth, the payload size of a BLE advertisement is very small due to power limitations and so instead all that gets sent in the payload is the following 8 bytes:

09 06 03 - Represents an AirPlay device
XX - A single byte that is used as a state machine, if the state of the AirPlay device changes (the password changes, or if the name changes, or if the availability of AirPlay goes from Everyone -> Anyone on the same network etc. etc. ) the byte increments by one indicating that the sender should repoll for the txtAirplay and txtRAOP records again.
c0 a8 01 XX - The IP address that the sender should connect to to retrieve the txtAirplay and txtRAOP records.

All that still needs to be implemented is using the Windows BLE library if on Windows and I assume using the linux library on mac (unless there is an alternative - Will need to look into this). Also I've just realised that it only gets the ethernet iface IP address atm, so people using Wi-Fi won't have their ip broadcast - I will fix this soon.

@fduncanh
Copy link
Collaborator

fduncanh commented Aug 18, 2024

can you take a look at SimpleBLE (a GPL v3 cross-platfom BLE implementation) ?
Could this be used?

https://github.com/OpenBluetoothToolbox/SimpleBLE

Unfortunately the large number of "issues" suggests its not quite mature yet....

@fduncanh
Copy link
Collaborator

fduncanh commented Aug 18, 2024

... as I've never worked in C before.

C++ with "extern C" wrappers for interface with C works. uxplay.cpp does this.

@connorh315
Copy link
Author

I remember seeing this library when I began trying to put it all together, since I didn't really know anything about C I stayed away from it because of the no. of issues (fixing my own problems was going to be enough, let alone having problems because the library was causing them). Will take a look at it tonight and try to use this library instead as that will make it a lot easier than implementing it differently for each platform.

@fduncanh
Copy link
Collaborator

BLE does look like a good feaure to add, thanks for your work on this

@connorh315
Copy link
Author

Thank you - Off topic but I've been fighting for a while to try to figure out how H265 works, struggling with wrapping my head around the HomeKit pairing process as it's not easy. Will keep trying though as I'm keen on figuring it out. Whilst I've got you - How do you reverse engineer all of this? I'm sure at the start you could use existing docs and research, but the things you're doing currently like HLS aren't really that well documented, and so I'm interested to know how you figure the stuff like that out when it's behind an encrypted channel of communication? Do you have a custom proxy solution that you use?

@fduncanh
Copy link
Collaborator

fduncanh commented Aug 18, 2024

HLS was a total mystery. incomplete pieces of a code with no ancestry in our own code base had appeared on github from time to time, with no license or provenance., until late last year, when someone interested noticed the full C++ code was recently published with a GPL license as "apsdk-public", but not in a usable state, as a demo and the fairplay substitute (playfair) were stripped out. It seems that a single author had been working on it since 2017. Luckily, looking back in the code history we were able to restore an earlier working demo, and see how to put back fairplay, which was indeed what was being used. (It's the only partial "crack" of fairplay that has been achieved, so I believe all open source and non-apple closed source implementations use it). Finally, by filling up the working demo with printf statements at every function call, the HLS workings became traceable and understandable. A working example that one can add printf's to is the key, when there is not much documentation.

apsdk-public has a C++ interface to a 2017 C hlsparser found on github. we borrowed this interface as apsdk is GPL, and gave C wrappers to it, and connected it to adapted UxPlay. . The remaining issues are GStreamer integration, so at some point uxplay will get HLS support (at least for youtube videos, since netflix has removed non-apple airplay support.)

Homekit pairing (from the client viewpoint) is semi documented at https://github.com/ejurgensen/pair_ap with server and client implementation. This also includes a client-only implementation of legacy-pairing it calls "fruit pairing" with SRP that was very useful for using on a true AppleTV to see what its SRP server responses were (this is the one-time pairing protocol, also used in homekit) , and fill in undocumented details by guess-and-check. https://github.com/philippe44/libraop was also very useful, but does not do homekit.

see https://github.com/FDH2/UxPlay/wiki/AirPlay2-protocol

@fduncanh
Copy link
Collaborator

I'm interested to know how you figure the stuff like that out when it's behind an encrypted channel of communication? Do you have a custom proxy solution that you use?

Unfortunately not. In legacy pairing (even with SRP authentication, which sets up what COULD be used for total communication encryption ) I was surprised to find that after all the work to implement SRP authentication, it doesnt enforce total encryption. But homekit does, as can been seen in https://github.com/ejurgensen/pair_ap, and seems to use (apple-modified) SRP with the "big random integer" upped from 2048 to 3072 bits.

@fduncanh
Copy link
Collaborator

fduncanh commented Aug 18, 2024

09 06 03 - Represents an AirPlay device
XX - A single byte that is used as a state machine, if the state of the AirPlay device changes (the password changes, or if the name changes, or if the availability of AirPlay goes from Everyone -> Anyone on the same network etc. etc. ) the byte increments by one indicating that the sender should repoll for the txtAirplay and txtRAOP records again.
c0 a8 01 XX - The IP address that the sender should connect to to retrieve the txtAirplay and txtRAOP records.

one design possibility is that the running uxplay writes its BLE message to a file that only exists while uxplay is running, and some helper function, running as root if that is needed, broadcasts it on bluetooth at appropriate intervals if it exists? something like that is implement in the -dacp option for interfacing with a remote controller for the iOS client.

I am assuming that the client responds on the network, not with reverse BLE?

@fduncanh
Copy link
Collaborator

fduncanh commented Aug 18, 2024

To keep it simple there are two advertising types; connectable and non-connectable. Non-connectable might be useful if you just need one-way communication and only need to broadcast a couple of bytes. One use case for this might for example be location awareness.

  • Are we talking about the connectable or non-connectable case in the above quote about BLE?

@thiccaxe
Copy link

I think apple generally uses the non-connectable BLE, for things like

  • airpod battery ads
  • Apple TV ads: (screen calibration, apple id login)

e.g https://github.com/MarketStreetCyber/Blabber/blob/main/impersonate/setup_appletv.py uses "ADV_NONCONN_IND" which I assume is non connectable

@connorh315
Copy link
Author

SimpleBLE won't be enough unfortunately - It doesn't seem to support broadcasting advertisements (and it took me 4 hours to include in the project). I'll have to have a go at writing an implementation for each platform.

We're talking about non-connectable here, as @thiccaxe said the ADV_NONCONN_IND. Meaning that the listening device (iOS devices) cannot connect to the device - As such, like you said, the client responds by sending an HTTP request to the IP address in the BLE advertisement.

@fduncanh
Copy link
Collaborator

@connorh315 Confirming your observation that simpleBLE doesnt do advertising, I found this discussion on the simpleBLE discord server: It also seems that simpleBLE development was previously supported by developer's previous employer, and has now stalled (he comments: For a project like this to prosper, raw manpower is not enough if it’s not coordinated, as it leads to a steady degradation of the code quality. Either by managing people or coding myself, this is work that needs to put food on the table in one way or another.)

covertagent

08/09/2023 10:19 AM
Hey Folks, Can SimpleBle enable Bluetooth and put the device in discovery mode? As far as I could check, there are samples to connect, list devices etc but I couldn't find any samples that can just enable the Bluetooth and put it in discovery mode. I found Bluetooth client-specific functionalities in this library but not the server side functionalities. Can anyone please help here?
ER!K

08/09/2023 10:37 AM
What would "discovery mode" refer to? A BLE peripheral doing advertising would be considered discoverable as long as the flags field of the advertisement payload is set accordingly. This would be purely done on the peripheral side and hence not related to SimpleBLE doing the central (scanning) role on a PC. SimpleBLE (currently) only supports the central role, it cannot do advertising or expose a GATT table or other peripheral functions.
covertagent

08/09/2023 10:50 AM
Thanks for the prompt response @er!K, Noob question, Do you know of any libraries that can do advertising?
ER!K

08/09/2023 10:55 AM
You could check https://github.com/kevincar/bless being a Python library (was kind of derived from Bleak). Did not use it myself yet, so no clues whether good or not.

@connorh315
Copy link
Author

I think that BLE on Windows is going to be a bit of a pain to implement, I can't find any reliable docs/examples on using the Bluetooth libraries to broadcast an advertisement. Perhaps for now, I could just make the functions empty when building for Windows? It's a bit of a cheap cop out but I don't have long before I go back to work and don't want to leave this open - All this means is that the feature will only work on Linux. What do we all think?

@fduncanh
Copy link
Collaborator

fduncanh commented Aug 20, 2024

That's fine.

If its activated by an option (e.g. -ble ) one can test for windows and reject the option with an error message at startup.
Just put some comment explaining what would be needed to get it working on windows for possible future use.

I am more worried about your earlier mention of running as root, etc.

can you explain a bit more ?

@fduncanh
Copy link
Collaborator

is this a useful ref?

https://punchthrough.com/creating-a-ble-peripheral-with-bluez/

ideally Uxplay would just write the advertisement that should be sent to a file that only exists while uxplay is running,and some bluez service (running as root) would detect that file, read it and transmit the contents with BLE. Is such a thing possible?

@connorh315
Copy link
Author

I've had a look at the link that you've sent, I am probably able to rewrite it all to use the D-Bus, however I'm not entirely sure that this circumvents using sudo. I could give it a go though. As an alternative, I have discovered that a user can run sudo setcap 'cap_net_raw,cap_net_admin=eip' ./uxplay and that will grant the necessary BTLE privileges to the binary. Additionally, I believe that the user may be able to add their user account to the bluetooth group to achieve a similar result.

Let me know whether this is suitable, as I do understand your concern with running UxPlay as sudo (especially since it seems to break GStreamer).

@fduncanh
Copy link
Collaborator

once a working prototype is available, one can see how to improve it.

Ideally uxplay would write a file with the BLE message to be sent, just like the -dacp option, and a separate helper script would periodically check for the existence of that file and if it is found send the BLE message.

UxPlay works fine as root, with the firewall switched off, I checked. This is fine for testing.

The main thing is to have a working prototype to start with.

@connorh315
Copy link
Author

What's the problem with the current prototype so I know what needs to be done to improve that atm? And just so I understand as well what's the reason you want a separate helper script rather than the solution being a part of the UxPlay binary?

@thiccaxe
Copy link

BLE is tangential to UxPlay and not really core.

I think it would make sense to use something like python for ble as it already has a (probably) better package (bleak).

Also, I am going to say with some confidence that ble will eventually run into issues like needing to be rebroadcasted, restarted, what is Bluetooth is turned of, etc. let a user script take care of that. It also allows faster iteration and the feature can be published quicker. Dont want to use python? Any language can read / watch a file

@fduncanh
Copy link
Collaborator

@connorh315 I haven't yet tested your prototype, if its working, that's great as a start.

but writing the platform-independent BLE message text to a file that something else reads and sends the message is a truly cross-platform solution.

@fduncanh fduncanh force-pushed the master branch 4 times, most recently from 7a14d4c to b1fb510 Compare December 20, 2024 23:19
@fduncanh fduncanh force-pushed the master branch 7 times, most recently from f2d8c03 to 35b1e9e Compare January 25, 2025 14:37
@fduncanh fduncanh force-pushed the master branch 4 times, most recently from bc2843a to f63a91c Compare February 16, 2025 01:15
@fduncanh fduncanh force-pushed the master branch 12 times, most recently from 01d48c6 to bc2d5a4 Compare February 23, 2025 17:37
@fduncanh fduncanh force-pushed the master branch 3 times, most recently from 29b6d03 to 68ed1d5 Compare February 25, 2025 00:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants